springboot服务url包含{}大括号特殊字符的问题
问题描述:
三方系统调用我方提供的接口(spring boot服务提供接口)时,当url中包含未经过urlencode的特殊字符大括号“{}”,则会报400,导致请求都无法正常处理。
针对使用tomcat容器的服务
增加如下配置即可解决url不支持大括号{}的问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置Spring boot支持在查询参数中加{}[]字符。
*
* @author jacky
* @since 2019/09/05
*/
public class SystemConfig {
public EmbeddedServletContainerFactory webServerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addConnectorCustomizers((connector) ->
connector.setProperty("relaxedQueryChars", "[]{}")
);
return factory;
}
}
针对使用webflux的springboot2.x服务
通过查看源码如下,当url包含大括号“{}”特殊字符时,会报Failed to get request URI: xxx 异常1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.server.reactive;
import java.net.URISyntaxException;
import java.util.function.BiFunction;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.commons.logging.Log;
import reactor.core.publisher.Mono;
import reactor.netty.http.server.HttpServerRequest;
import reactor.netty.http.server.HttpServerResponse;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpLogging;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
/**
* Adapt {@link HttpHandler} to the Reactor Netty channel handling function.
*
* @author Stephane Maldini
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {
private static final Log logger = HttpLogging.forLogName(ReactorHttpHandlerAdapter.class);
private final HttpHandler httpHandler;
public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
Assert.notNull(httpHandler, "HttpHandler must not be null");
this.httpHandler = httpHandler;
}
public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
try {
ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
if (request.getMethod() == HttpMethod.HEAD) {
response = new HttpHeadResponseDecorator(response);
}
return this.httpHandler.handle(request, response)
.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
}
catch (URISyntaxException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to get request URI: " + ex.getMessage());
}
reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
return Mono.empty();
}
}
}
暂时没找到通过配置可以解决的方案,只能修改覆盖这个类的源码以达到支持的目的。
修改覆盖源码的方式如下:
org.springframework.http.server.reactive.ReactorServerHttpRequest1
2
3
4
5
6private static URI initUri(HttpServerRequest request) throws URISyntaxException {
Assert.notNull(request, "HttpServerRequest must not be null");
// 针对 特殊字符 { } 做替换处理
String requestUri = resolveRequestUri(request).replace("{", "%7B").replace("}", "%7D");
return new URI(resolveBaseUrl(request).toString() + requestUri);
}